{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    " # <center>第3章 常用数据结构</center>\n",
    "  \n",
    " <br> \n",
    "  \n",
    "  - [3.1 序列](#3.1-序列)\n",
    "    - [3.1.1 序列的种类](#3.1.1-序列的种类)\n",
    "    - [3.1.2 序列的基本操作](#3.1.2-序列的基本操作)\n",
    "  - [3.2 列表](#3.2-列表)\n",
    "    - [3.2.1 列表的定义](#3.2.1-列表的定义)\n",
    "    - [3.2.2 列表元素操作](#3.2.2-列表元素操作)\n",
    "    - [3.2.3 列表推导式](#3.2.3-列表推导式)\n",
    "    - [3.2.4 栈](#3.2.4-栈)\n",
    "  - [3.3 元组](#3.3-元组)\n",
    "    - [3.3.1 元组的定义与使用](#3.3.1-元组的定义与使用)\n",
    "    - [3.3.2 元组的不可变陷阱](#3.3.2-元组的不可变陷阱)\n",
    "    - [3.3.3 生成器推导式*](#3.3.3-生成器推导式*)\n",
    "  - [3.4 集合](#3.4-集合)\n",
    "    - [3.4.1 集合的定义](#3.4.1-集合的定义)\n",
    "    - [3.4.2 常用集合操作方法](#3.4.2-常用集合操作方法)\n",
    "    - [3.4.3 集合推导式](#3.4.3-集合推导式)\n",
    "    - [3.4.4 排列组合](#3.4.4-排列组合)\n",
    "  - [3.5 字典](#3.5-字典)\n",
    "    - [3.5.1 字典的定义](#3.5.1-字典的定义)\n",
    "    - [3.5.2 字典常用操作方法](#3.5.2-字典常用操作方法)\n",
    "    - [3.5.3 字典推导式](#3.5.3-字典推导式)\n",
    "  - [3.6 字符串](#3.6-字符串)\n",
    "    - [3.6.1 字符串的定义](#3.6.1-字符串的定义)\n",
    "    - [3.6.2 常用字符串处理方法](#3.6.2-常用字符串处理方法)\n",
    "    - [3.6.3 字符串格式化](#3.6.3-字符串格式化)\n",
    "  - [3.7 二进制序列](#3.7-二进制序列)\n",
    "    - [3.7.1 字节串的原理](#3.7.1-字节串的原理)\n",
    "    - [3.7.2 字节串的应用](#3.7.2-字节串的应用)\n",
    "  - [3.8 高级数据结构](#3.8-高级数据结构)\n",
    "    - [3.8.1 `collection`模块](#3.8.1-collection模块)\n",
    "    - [3.8.1 `array.array`](#3.8.1-array.array)\n",
    "    - [3.8.3 其他有用的数据结构](#3.8.3-其他有用的数据结构)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 3.1 序列\n",
    "\n",
    "### 3.1.1 序列的种类\n",
    "\n",
    "#### 容器序列与扁平序列\n",
    "- 容器序列（Container Sequences）\n",
    "  - 容器序列中存储的并不是对象本身，而是对象的引用。因此，容器序列中可以存放不同类型的数据。\n",
    "  - `list`、`tuple`、`collections.deque`\n",
    "- 扁平序列（Flat Sequences）\n",
    "  - 扁平序列中存储的是对象的取值（即对象自身），要求一段连续的内存空间。因此，扁平序列中的对象必须具有相同的类型。\n",
    "  - `str`、`bytes`、`bytearray`、`array.array`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 可变序列与不可变序列\n",
    "- 可变序列\n",
    "  - 序列中存储的元素可以被添加、删除、修改\n",
    "  - 常见的可变序列有`list`、`bytearray`、`array.array`、`collections.deque`\n",
    "- 不可变序列\n",
    "  - 序列创建之后，其中的元素不能再添加、删除修改\n",
    "  - 常见的不可变序列有`tuple`、`str`、`bytes`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 不可变的含义\n",
    "    - “不可变”是指其中存储的引用是不能改变的，并不意味着引用指向的对象是不可改变的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'tuple' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-3-4623fcbd5836>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mt\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'w'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mt\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "t = (1, 'w', [4, 2])\n",
    "t[2] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 'w', [0, 2])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t[2][0]=0\n",
    "t"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.1.2 序列的基本操作\n",
    "\n",
    "- 索引\n",
    "  - 索引取值可以为负\n",
    "  \n",
    "  \n",
    " <center><img src=\"./figures/fig3-1.png\" width=\"25%\"/><center>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "7\n",
      "8 8\n"
     ]
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8, 5, 7]\n",
    "print(lst[0])\n",
    "print(lst[-1])\n",
    "print(lst[3], lst[-3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 切片\n",
    "  - 形如`i:j:k`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "lst[1:5] =  [4, 2, 8, 5]\n",
      "lst[:-1] =  [1, 4, 2, 8, 5]\n",
      "lst[-5:-2] =  [4, 2, 8]\n",
      "lst[:] =  [1, 4, 2, 8, 5, 7]\n",
      "lst[::2] = [1, 2, 5]\n"
     ]
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8, 5, 7]\n",
    "print('lst[1:5] = ', lst[1:5])\n",
    "print('lst[:-1] = ', lst[:-1])\n",
    "print('lst[-5:-2] = ', lst[-5:-2])\n",
    "print('lst[:] = ', lst[:])\n",
    "print('lst[::2] =', lst[::2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 连接与重复"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 4, 2, 8, 5, 7)"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(1, 4, 2) + (8, 5, 7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "can only concatenate list (not \"tuple\") to list",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-17-fce18c4ee146>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m8\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m7\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: can only concatenate list (not \"tuple\") to list"
     ]
    }
   ],
   "source": [
    "[1, 4, 2] + (8, 5, 7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 2, 1, 4, 2, 1, 4, 2]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[1, 4, 2] * 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Python Python Python '"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "3 * 'Python '"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 元素检查\n",
    "  - 判断一个数值或对象是否包含在序列中\n",
    "  - 可使用`in`或`not in`运算符\n",
    "  - `index`方法\n",
    "  - `count`方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "lst = ['Python', 'Java', 'C++']\n",
    "print('Python' in lst)\n",
    "print('C#' not in lst)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst.index('Python')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = 'Hello Python'\n",
    "s.count('o')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 其他序列操作\n",
    "  - `len`：返回序列的长度\n",
    "  - `max`：返回序列中的最大值\n",
    "  - `min`：返回序列中的最小值\n",
    "  - `sum`：序列元素值求和\n",
    "  - `sorted`：对序列元素进行排序，不可变序列排序返回一个排序后的列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\n",
      "8\n",
      "1\n",
      "27\n"
     ]
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8, 5, 7]\n",
    "print(len(lst))\n",
    "print(max(lst))\n",
    "print(min(lst))\n",
    "print(sum(lst))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 4, 5, 7, 8]\n",
      "[8, 7, 5, 4, 2, 1]\n"
     ]
    }
   ],
   "source": [
    "print(sorted(lst))\n",
    "print(sorted(lst, reverse=True))  # 逆序排序"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 3.2 列表\n",
    "\n",
    "### 3.2.1 列表的定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['P', 'y', 't', 'h', 'o', 'n']"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8, 5, 7]\n",
    "lst = list() # lst = []\n",
    "s = 'Python'\n",
    "list(s)  # list将字符串转为列表"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.2.2 列表元素操作\n",
    "  \n",
    "- 添加元素：`list.append(obj)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 2, 8, 5]"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8]\n",
    "lst.append(5)\n",
    "lst"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 插入元素： `list.insert(index, obj)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, [0, 0], 2, 5, 8]"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst = [1, 4, 2, 5]\n",
    "lst.insert(4, 8)\n",
    "lst\n",
    "lst.insert(2, [0, 0])\n",
    "lst"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 扩充元素：`list.extend(seq_obj)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 2, 8, 5, 7]"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8]\n",
    "lst.extend([5, 7])\n",
    "lst"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 删除元素\n",
    "  - `del`函数\n",
    "  - `list.remove(obj)`方法\n",
    "  - `list.clear`方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4, 2, 8, 5, 7]\n",
      "[4, 2, 8, 5]\n",
      "[]\n"
     ]
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8, 5, 7]\n",
    "del lst[0]\n",
    "print(lst)\n",
    "lst.remove(7)\n",
    "print(lst)\n",
    "lst.clear()\n",
    "print(lst)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 修改元素值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 4, 2, 7]\n",
      "[5, 7, 2, 7]\n",
      "[0, 7, 0, 7]\n",
      "[0, 7, 4, 2, 4, 2, 0, 7]\n"
     ]
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8]\n",
    "lst[-1] = 7              # 索引修改\n",
    "print(lst)\n",
    "lst[0:2] = [5, 7]        # 修改前两个元素\n",
    "print(lst)\n",
    "lst[::2] = [0, 0]        # 修改索引为偶数的元素\n",
    "print(lst)\n",
    "lst[2:2] = [4, 2, 4, 2]  # 插入多个元素\n",
    "print(lst)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 排序\n",
    "  - `sorted`\n",
    "  - `list.sort`\n",
    "  - 区别\n",
    "    - `sorted`函数会复制出一份新的列表，在新的列表上排序，原来的列表不会被改变，而`list.sort`方法则在原列表上排序\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "lst = [1, 4, 2, 8, 5, 7]\n",
    "lst_id = id(lst)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst_sorted = sorted(lst)\n",
    "lst_id == id(lst_sorted)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst.sort()\n",
    "lst_id == id(lst)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 列表的`reverse`方法用于反转列表元素的顺序。该方法也是在序列上操作，不会返回新的序列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "[7, 5, 8, 2, 4, 1]\n"
     ]
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8, 5, 7]\n",
    "lst_id = id(lst)\n",
    "lst.reverse()\n",
    "print(lst_id == id(lst))\n",
    "print(lst)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 复制\n",
    "  - `list.copy`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 4, 5, 7, 8]\n",
      "[1, 4, 2, 8, 5, 7]\n"
     ]
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8, 5, 7]\n",
    "lst_new = lst.copy()\n",
    "lst_new.sort()\n",
    "print(lst_new)\n",
    "print(lst)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 浅复制，`list.copy`或`copy.copy`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 4, 2, 8, [0, 7]]\n",
      "[1, 4, 2, 8, [0, 7]]\n"
     ]
    }
   ],
   "source": [
    "lst = [1, 4, 2, 8, [5, 7]]\n",
    "lst_new = lst.copy()\n",
    "lst_new[-1][0] = 0\n",
    "print(lst_new)\n",
    "print(lst)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 深复制，`copy.deepcopy`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 4, 2, 8, [0, 7]]\n",
      "[1, 4, 2, 8, [5, 7]]\n"
     ]
    }
   ],
   "source": [
    "from copy import deepcopy\n",
    "lst = [1, 4, 2, 8, [5, 7]]\n",
    "lst_new = deepcopy(lst)\n",
    "lst_new[-1][0] = 0\n",
    "print(lst_new)\n",
    "print(lst) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 3.2.3 列表推导式\n",
    "\n",
    "- 在Python中应当尽可能减少循环语句的使用\n",
    "- 能使用列表推导式实现时，就不要使用循环\n",
    "- 列表推导式的语法形式为：\n",
    "\n",
    "```\n",
    "[表达式 for...in iter_obj]\n",
    "```\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 2, 8, 5, 7]"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst_str = ['1', '4', '2', '8', '5', '7']\n",
    "lst = [int(s) for s in lst_str]\n",
    "lst"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 同时遍历多个序列\n",
    "```\n",
    "[表达式 for...in iter_obj1 for... in iter_obj2 ...]\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(11, 21, 32),\n",
       " (11, 22, 33),\n",
       " (11, 23, 34),\n",
       " (12, 21, 33),\n",
       " (12, 22, 34),\n",
       " (12, 23, 35),\n",
       " (13, 21, 34),\n",
       " (13, 22, 35),\n",
       " (13, 23, 36)]"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst1 = [11, 12, 13]\n",
    "lst2 = [21, 22, 23]\n",
    "lst_new = [(e1, e2, e1 + e2) for e1 in lst1 for e2 in lst2]\n",
    "lst_new"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- `if`子句\n",
    "\n",
    "```\n",
    "[表达式 for...in list_obj1 for... in list_obj2 ... if 逻辑表达式]\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[32, 34, 36]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst1 = [11, 12, 13]\n",
    "lst2 = [21, 22, 23]\n",
    "lst_add = [e1 + e2 for i, e1 in enumerate(lst1) for j, e2 in enumerate(lst2) if i == j]\n",
    "lst_add\n",
    "\n",
    "nes_lst = [e1 + e2 for e1, e2 in zip(lst1, lst2)]\n",
    "nes_lst"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 列表推导式与循环的性能比较"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "from time import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.1165800094604492\n"
     ]
    }
   ],
   "source": [
    "start_time = time()\n",
    "l = []\n",
    "for i in range(10000000):\n",
    "    l.append(i)\n",
    "print(time()-start_time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.7393479347229004\n"
     ]
    }
   ],
   "source": [
    "start_time = time()\n",
    "l = [i for i in range(10000000)]\n",
    "print(time()-start_time)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 更快速的方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.5307950973510742\n"
     ]
    }
   ],
   "source": [
    "start_time = time()\n",
    "l = list(range(10000000))\n",
    "print(time()-start_time)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.2.4 栈\n",
    "- 栈的特征\n",
    "  - 后进先出（Last In First Out）\n",
    "  - `list.pop`方法的作用是弹出列表的最后一个元素\n",
    "  - Python列表没有push方法，但可使用`append`方法替代"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "stack = [1, 4, 2, 8, 5, 7]\n",
    "print(stack.pop())\n",
    "stack.append(7)\n",
    "print(stack)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 也可以利用Python动态语言的特性，使得栈的操作更加附合使用习惯"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "7\n",
      "[1, 4, 2, 8, 5]\n",
      "[1, 4, 2, 8, 5, 7]\n"
     ]
    }
   ],
   "source": [
    "stack = [1, 4, 2, 8, 5, 7]\n",
    "pop = stack.pop\n",
    "push = stack.append\n",
    "print(pop())\n",
    "print(stack)\n",
    "push(7)\n",
    "print(stack)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 3.3 元组\n",
    "\n",
    "### 3.3.1 元组的定义与使用\n",
    "\n",
    "- 定义\n",
    "  - `()`\n",
    "  - `tuple`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "()\n",
      "(1, 4, 2, 8, 5, 7)\n",
      "('P', 'y', 't', 'h', 'o', 'n')\n"
     ]
    }
   ],
   "source": [
    "t = tuple()\n",
    "print(t)\n",
    "lst = [1, 4, 2, 8, 5, 7]\n",
    "t = tuple(lst)\n",
    "print(t)\n",
    "s = 'Python'\n",
    "t = tuple(s)\n",
    "print(t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 当元组中只有一个元素时，使用`()`定义必须要在后边加一个逗号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "<class 'int'>\n"
     ]
    }
   ],
   "source": [
    "t = (1)\n",
    "print(t)\n",
    "print(type(t))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'tuple'>\n"
     ]
    }
   ],
   "source": [
    "t = (1,)\n",
    "print(type(t))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 元组的操作\n",
    "  - 索引、切片、连接、重复、成员资格检查，以及长度、最大值、最小值等\n",
    "  - 元素不能改变"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.3.2 元组的不可变陷阱\n",
    "\n",
    "- 如果将一个可变序列作为元组的元素，那么这个可变序列的元素是否能够被改变呢?\n",
    "  - 元组同时还是一个容器类型，其中存储的并不是元素自身而是 元素的引用\n",
    "  - “不可变”是指其中存储的引用是不能改变的，并不意味着引用指向的对 象是不可改变的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'tuple' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-2-018f412d059b>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mt\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'w'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mt\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0mt\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "t = (1, 'w', [4, 2])\n",
    "t[2] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 'w', [0, 2])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t[2][0]=0 \n",
    "t"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.3.3 生成器推导式*\n",
    "\n",
    "- 在定义时，生成器推导式与元组的关系，也列表生成器与列表的关系相似\n",
    "\n",
    "```\n",
    "(表达式 for...in iter_obj)\n",
    "```\n",
    "- 生成器推导式中也可以包含多个`for`子句以及`if`子句\n",
    "- 本质上，生成器推导式与元组其实关系不大\n",
    "  - 它返回的是一个生成器\n",
    "  - 生成器是一种特殊的可迭代对象，它并没有保存所有的无素，而是仅仅定义了获取下一个元素的方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 性能比较"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [],
   "source": [
    "from time import time\n",
    "from sys import getsizeof"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.670072078704834\n",
      "81528048\n"
     ]
    }
   ],
   "source": [
    "start_time = time()\n",
    "lst = [i for i in range(10000000)]\n",
    "print(time()-start_time)\n",
    "print(getsizeof(lst))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.274482727050781e-05\n",
      "112\n"
     ]
    }
   ],
   "source": [
    "start_time = time()\n",
    "g = (i for i in range(10000000))\n",
    "print(time()-start_time)\n",
    "print(getsizeof(g))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 3.4 集合\n",
    "\n",
    "### 3.4.1 集合的定义\n",
    "\n",
    "- 可变集合`set`\n",
    "  - 可以使用`set()`定义一个空集合或将其他可迭代对象转为一个可变集合类型\n",
    "- 不可变集合`frozenset`\n",
    "  - 可以定义一个空的不可变集合，或者将其他可迭代对象转为一个不可变集合\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1, 2, 4, 7}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = {1, 4, 2, 1, 2, 7}\n",
    "s"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 利用集合不允许重复元素的特点，可以非常高效地去除序列中的重复元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "20000\n",
      "10000\n"
     ]
    }
   ],
   "source": [
    "l = list(range(10000)) * 2\n",
    "print(len(l))\n",
    "s = set(l)\n",
    "print(len(s))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.4.2 常用集合操作方法\n",
    "\n",
    "- 集合元素操作\n",
    "  - 集合是一种可迭代对象，可以利用循环语句来遍历每个元素。但由于元素是无序的，因此无法像列表那样利用索引或切片访问单个或部分元素。不过，可变集合可以添加或去除其中的元素。常见的集合元素操作见下表\n",
    "\n",
    "| 方法          | 功能         | 示例                   | 结果        |\n",
    "| ------------- | ------------ | ---------------------- | ----------- |\n",
    "| `set.add`     | 添加一个元素 | `{1,4,2}.add(8)`       | `{8,1,2,4}` |\n",
    "| `set.update`  | 添加多个元素 | `{1,4}.update({2,8})`  | `{8,1,2,4}` |\n",
    "| `set.remove`  | 去除元素     | `{1,4,2,8}.remove(0)`  | `KeyError`  |\n",
    "| `set.discard` | 去除元素     | `{1,4,2,8}.discard(0)` | `{8,1,2,4}` |\n",
    "| `set.pop`     | 随机弹出元素 | `{1,4,2,8}.pop()`      |           |\n",
    "| `set.clear`   | 清空集合     | `{1,4,2,8}.clear()`    | `{}`        |\n",
    "\n",
    "此外，用于求元素数量（`len`）、最大值（`max`）、最小值（`min`）、求和（`sum`）等函数对集合对象也有效\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 集合运算\n",
    "  - Python中的集合类型具有和数学中集合相同的交、并、差，以及对称差等集合运算。集合运算可以使用运算符，也可以使用集合对象的方法实现，见下表\n",
    "Python中的集合类型具有和数学中集合相同的交、并、差，以及对称差等集合运算。集合运算可以使用运算符，也可以使用集合对象的方法实现，见下表\n",
    "\n",
    "| 运算符 | 方法        | 运算                | 示例            | 结果        |\n",
    "| ------ | ------ | -------------------------- | --------------- | ----------- |\n",
    "| `&`   | `set.intersection`     | 交        | `{1,2,3} & {4,2}` | `{2}` |\n",
    "| `\\|`   | `set.union`      | 并            | `{1,2,3} \\| {4,2}` | `{1,2,3,4}` |\n",
    "| `-`    | `set.difference`   | 差          |      `{1,2,3} - {4,2}`         | `{1,3}` |\n",
    "| `^`    | `set.symmetric_difference`  | 对称差|         `{1,2,3} ^ {4,2}`         | `{1,3,4}` |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 关系检查\n",
    "  - 判断集合中是否包含一个元素的方法与序列相同，使用`in`或`not in`运算符。集合类型提供了相应的方法来判断两个集合之间的关系。见下表\n",
    "\n",
    "\n",
    "| 方法/运算符      | 功能         | 示例                        | 结果   |\n",
    "| ---------------- | ------------ | --------------------------- | ------ |\n",
    "| `set.isdisjoint` | 交集是否为空 | `{1,2,3}.isdisjoint({1,2})` | `False` |\n",
    "| `set.issubset`   | 是否为子集   | `{1,2}.issubset({1,2,3})`   | `True` |\n",
    "| `set.issuperset` | 是否为超集   | `{1,2,3}.issuperset({1,2})` | `True` |\n",
    "\n",
    "此外，两个集合对象关系判断更方便的方法是使用比较运算符：集合相等（`==`）、集合不全相等（`！=`）、子集（`<=`）、真子集（`<`）、超集（`>=`）、真超集（`>`）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.4.3 集合推导式\n",
    "\n",
    "- 集合推导式与列表推导式和生成器推导式的概念相似，可以不使用循环基于一个可迭代对象创建一个集合。集合推导式的语法形式与列表推导式的唯一区别就是将`[]`换为`{}`：\n",
    "\n",
    "```\n",
    "{表达式 for...in iter_obj}\n",
    "```\n",
    "\n",
    "- 当然，集合推导式中也可以包含多个`for`子句以及`if`子句"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "有 3 人参加了考试\n"
     ]
    }
   ],
   "source": [
    "scores = [\n",
    "    ('张三', '数学', 90),\n",
    "    ('李四', '数学', 80),\n",
    "    ('王五', '英语', 85),\n",
    "    ('张三', '英语', 95)\n",
    "]\n",
    "name_set = {e[0] for e in scores}  # 集合推导式\n",
    "print(f'有 {len(name_set)} 人参加了考试')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.4.4 排列组合\n",
    "\n",
    "- 排列，是从$n$个元素中不重复地取出$m$个并按一定的顺序排列，称为一个排列。所有可能的排列的个数，称为排列数，记为：\n",
    "$$\n",
    "A_n^m = n(n-1)(n-2)\\cdots(n-m+1) = \\frac{n!}{(n-m)!}\n",
    "$$\n",
    "- 组合，是从$n$个元素中不重复地最出$m$个，称为一个组合。所有可能的组合的总数称为组合数，记为：\n",
    "$$\n",
    "C_n^m= \\frac{P_n^m}{P_m} = \\frac{n!}{m!(n-m)!}\n",
    "$$\n",
    "\n",
    "- Python的`itertools`包提供了两个函数`permutations`和`combinations`分别用于排列和组合的运算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(8, 1), (8, 2), (8, 4), (1, 8), (1, 2), (1, 4), (2, 8), (2, 1), (2, 4), (4, 8), (4, 1), (4, 2)]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[(8, 1), (8, 2), (8, 4), (1, 2), (1, 4), (2, 4)]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from itertools import permutations, combinations\n",
    "s = {1, 4, 2, 8}\n",
    "p = permutations(s, 2)     # 排列\n",
    "print(list(p))\n",
    "c = combinations(s, 2)     # 组合\n",
    "list(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 3.5 字典\n",
    "\n",
    "### 3.5.1 字典的定义\n",
    "\n",
    "- 以键-值对（key-value）的形式存储元素，可以使用`{key:value, ...}`的形式定义\n",
    "- `{}`可以用于定义一个空词典。字典的类型为`dict`，空字典也可以使用`dict()`定义。也可以使用`dict()`定义字典，或者将一个由元组组成的列表转换为字典"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a': 1, 'b': 4, 'c': 2, 'd': 8}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = dict(a=1, b=4, c=2, d=8)\n",
    "d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a': 1, 'b': 4, 'c': 2, 'd': 8}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst = [('a', 1), ('b', 4), ('c', 2), ('d', 8)]\n",
    "dict(lst)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.5.2 字典常用操作方法\n",
    "\n",
    "- 字典元素的操作\n",
    "  - 字典元素的访问、修改、删除使用key实现\n",
    "  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = {'a':1, 'b':4, 'c':2, 'd':8}\n",
    "d['a']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a': 1, 'b': 4, 'c': 2, 'd': 8, 'e': 5}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d['e'] = 5\n",
    "d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a': 1, 'b': 4, 'c': 2, 'd': 8}"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "del d['e']\n",
    "d"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "  - 在使用key访问元素时，若key不存在会抛出`KeyError`。更安全的方法是使用字典对象的`get`方法，key不存在的时返回`None`或者指定的默认值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "ename": "KeyError",
     "evalue": "'e'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-15-756b0088b919>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0md\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;34m'a'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'b'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'c'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'd'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m8\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0md\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'e'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mKeyError\u001b[0m: 'e'"
     ]
    }
   ],
   "source": [
    "d = {'a':1, 'b':4, 'c':2, 'd':8}\n",
    "d['e']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d.get('e') is None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'no exist'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d.get('e', 'no exist')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 字典的遍历\n",
    "  - 字典的遍历有多种方法，可以只遍历所有的key或value，也可以遍历所有的key-value对。分别通过如下三个方法实现：\n",
    "    \n",
    "     - `dict.keys`：返回字典对象中所有key组成的可迭代对象\n",
    "     - `dict.values`：返回由所有value组成的可迭代对象\n",
    "     - `dict.items`：返回由元组`(key, value)`组成的可迭代对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dict_keys(['a', 'b', 'c', 'd'])\n",
      "dict_values([1, 4, 2, 8])\n",
      "dict_items([('a', 1), ('b', 4), ('c', 2), ('d', 8)])\n"
     ]
    }
   ],
   "source": [
    "d = {'a':1, 'b':4, 'c':2, 'd':8}\n",
    "print(d.keys())\n",
    "print(d.values())\n",
    "print(d.items())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a 1\n",
      "b 4\n",
      "c 2\n",
      "d 8\n",
      "a 1\n",
      "b 4\n",
      "c 2\n",
      "d 8\n"
     ]
    }
   ],
   "source": [
    "d = {'a': 1, 'b': 4, 'c':2, 'd': 8}\n",
    "for key in d.keys():          # 方法1\n",
    "    print(key, d[key])\n",
    "\n",
    "for key, value in d.items():  # 方法2\n",
    "    print(key, value)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 字典的其他操作\n",
    "\n",
    "| 方法           | 功能                       | 示例                                     | 结果               |\n",
    "| -------------- | -------------------------- | ---------------------------------------- | ------------------ |\n",
    "| `dict.clear`   | 清空字典                   | `{'a':1, 'b':4, 'c':2, 'd':8}.clear()`   | `{}`               |\n",
    "| `dict.popitem` | 随机弹出一个key-value对    | `{'a':1, 'b':4, 'c':2, 'd':8}.popitem()` | `('d', 7)`         |\n",
    "| `dict.pop`     | 弹出指定的值               | `{'a':1, 'b':4, 'c':2, 'd':8}.pop('a')`  | `1`                |\n",
    "| `dict.update`  | 利用另一个字典更新当前字典 | `{'a':4, 'b':2}.update({'a':1, 'b':3})`  | `{'a': 1, 'b': 3}` |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.5.3 字典推导式\n",
    "\n",
    "- 字典推导式与列表推导式和集合推导式类似，能够不使用循环的情况下创建一个字典。其语法形式为：\n",
    "\n",
    "```\n",
    "{key:value for key, value in iter_obj}\n",
    "```\n",
    "- 当然，字典推导式中也可以包含多个`for`子句以及`if`子句，用于在更复杂的情况下构造字典"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'Python': 6, 'Java': 4, 'C': 1, 'C++': 3, 'C#': 2}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "languages = ['Python', 'Java', 'C', 'C++', 'C#']\n",
    "language_len = {e: len(e) for e in languages}\n",
    "language_len"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 3.6 字符串\n",
    "\n",
    "### 3.6.1 字符串的定义\n",
    "\n",
    "- `'Python'`\n",
    "- `\"Python\"`\n",
    "- `'''Python'''`\n",
    "- `\"\"\"Python\"\"\"`\n",
    "- `u'Python'`\n",
    "- `r'Python'`\n",
    "- `b'Python'`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.6.2 常用字符串处理方法\n",
    "\n",
    "- 字符串大小写转换\n",
    "\n",
    "| 操作           | 功能             | 示例输入             | 示例操作       | 示例输出           |\n",
    "| :-------------- | :---------------- |: -------------------- | :-------------- | :------------------ |\n",
    "| `str.lower`    | 所有字母转为小写 | `s='Python'`         | `s.lower()`    | `'python'`         |\n",
    "| `str.upper`    | 所有字母转为大写 | `s='Python'`         | `s.upper()`    | `PYTHON`           |\n",
    "| `str.swapcase` | 大小写互换       | `s='Python'`         | `s.swapcase()` | `'pYTHON'`         |\n",
    "| `str.title`    | 单词首字母大写   | `s='python is easy'` | `s.title()`    | `'Python Is Easy'` |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 空白去除与填充\n",
    "\n",
    "|操作|功能|示例输入|示例操作|示例输出|\n",
    "|:---|:---|:---|:---|:---|\n",
    "|`str.strip`| 去除两侧空白 | `s=' Python '` | `s.strip()` | `'Python'` |\n",
    "|`str.lstrip`| 去除左侧空白 | `s=' Python '` | `s.lstrip()` | `'Python '`|\n",
    "|`str.rstrip`| 去除右侧空白 | `s=' Python '` | `s.rstrip()` | `' Python'` |\n",
    "|`str.center`| 两侧填充符号 | `s='Python'` | `s.center(10, '*')` | `'**Python**'` |\n",
    "|`str.ljust`| 左侧填充符号 | `s='Python'` | `s.ljust(10, '*')` | `'Python****'` |\n",
    "|`str.rjust`| 右侧填充符号 | `s='Python'` | `s.rjust(10, '*')` | `'****Python'` |\n",
    "|`str.zfill`|左侧补0|`s='Python'`|`s.zfill(10)`|`'0000Python'`|"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 字符串查找与替换\n",
    "\n",
    "|操作|功能|示例输入|示例操作|示例输出|\n",
    "|:---|:---|:---|:---|:---|\n",
    "|`str.find`| 从左查找子串，<br>返回索引或-1 | `s='Python is easy'` | `s.find('y')` | `1` |\n",
    "|`str.rfind`| 从右查找子串，<br>返回索引或-1 | `s='Python is easy'` | `s.rfind('y')` | `13` |\n",
    "|`str.index`| 从左查找子串，<br>返回索引或错误 | `s='Python is easy'` | `s.index('y')` | `1` |\n",
    "|`str.rindex`| 从右查找子串，<br>返回索引或错误 | `s='Python is easy'` | `s.rindex('y')` | `13` |\n",
    "|`str.replace`| 替换子串 | `s='Python is easy'` | `s.replace('is', '')` | `'Python  easy'` |\n",
    "|`str.expandtabs`| Tab符替换为空格 | `s='Python\\teasy'` | `s.expandtabs(2)` | `'Python  easy'` |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 字符串翻译\n",
    "  - 字符互换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'123321'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trans=str.maketrans('abc', '123')\n",
    "s = 'abccba'\n",
    "s.translate(trans)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 字符串分割\n",
    "\n",
    "|操作|功能|示例输入|示例操作|示例输出|\n",
    "|:---|:---|:---|:---|:---|\n",
    "|`str.split`| 从左侧分割 | `s='a,b,c'` | `s.split(',')` | `['a', 'b', 'c']` |\n",
    "|`str.rsplit`| 从右侧分割 | `s='a,b,c'` | `s.rsplit(',', 1)` | `['a,b', 'c']` |\n",
    "|`str.splitlines`| 按行分割 | `s='a\\nb\\nc'` | `s.splitlines()` | `['a', 'b', 'c']` |\n",
    "|`str.partition`| 从左侧切断 | `s='a,b,c'` | `s.partition(',')` | `('a', ',', 'b,c')` |\n",
    "|`str.rpartition`| 从右侧切断 | `s='a,b,c'` | `s.rpartition(',')` | `('a,b', ',', 'c')` |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 连接"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1-4-2-8'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst = ['1', '4', '2', '8']\n",
    "'-'.join(lst)\n",
    "'1-4-2-8'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 字符串的特征测试\n",
    "\n",
    "\n",
    "\n",
    "| 方法          | 功能                | 示例                 | 方法调用              | 输出    |\n",
    "| :------------ | :------------------ | :------------------- | :-------------------- | :------ |\n",
    "| `isalnum`     | 是否仅含字母或数字  | `s='Abc123'`         | `s.isalnum()`         | `True`  |\n",
    "| `isdecimal`   | 是否仅含十进制数字  | `s='123'`            | `s.isdecimal()`       | `True`  |\n",
    "| `isalpha`     | 是否仅含字母        | `s='Abc123'`         | `s.isalpha()`         | `Fasle` |\n",
    "| `isdigit`     | 是否仅含整数数字    | `s='123.0'`          | `s.isdigit()`         | `False` |\n",
    "| `isnumeric`   | 是否仅含数字        | `s='123'`            | `s.isnumeric()`       | `True`  |\n",
    "| `isupper`     | 是否不含小写符号    | `s='ABC123'`         | `s.isupper()`         | `True`  |\n",
    "| `islower`     | 是否不含大写        | `s='abc123'`         | `s.islower()`         | `True`  |\n",
    "| `isspace`     | 是否仅含空白符号    | `s=' \\t'`            | `s.isspace()`         | `True`  |\n",
    "| `istitle`     | 是否首字母大写      | `s='Python is easy'` | `s.istitle()`         | `False` |\n",
    "| `isascii`     | 是否仅含 ASCII 符号 | `s='Python 编程'`    | `s.isascii()`         | `False` |\n",
    "| `isprintable` | 是否为可打印符号    | `s='\\t'`             | `s.isprintable()`     | `False` |\n",
    "| `startswith`  | 是否以给定子串开头  | `s='Abc123'`         | `s.startswith('Abc')` | `True`  |\n",
    "| `endswith`    | 是否以给定子串结尾  | `s='Abc123'`         | `s.endswith('123')`   | `True`  |\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 字符串的动态执行*\n",
    "  - 函数\n",
    "    - `exec`：作为脚本代码执行\n",
    "    - `eval`：作为表达式执行\n",
    "  - 存在安全隐患"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello Python!\n"
     ]
    }
   ],
   "source": [
    "exec('print(\"Hello Python!\")')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eval('5 > 3')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 8, 2, 7]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst = eval('[1, 4, 8, 2, 7]')\n",
    "lst"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.6.3 字符串格式化\n",
    "\n",
    "- 将一个字符串模板中的占位符替换为所需输出的具体值，从而实现复杂的字符串输出\n",
    "- 三种格式化方法\n",
    "  - `%`符号\n",
    "  - `format`方法\n",
    "  - f-string"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 使用 `%`符号格式化字符串\n",
    "\n",
    "与C语言中printf函数的使用方法相似。\n",
    "\n",
    "利用`%`符号格式化字符串时，占位符以`%`开头，其语法形式为`%[(name)][flags][width].[precision]type`\n",
    "\n",
    "- `(name)`：可选，用于以字典的形式传递占位数值\n",
    "- `flags`：可选，可能的取值有\n",
    "  - `+`    右对齐；正数前加正好，负数前加负号\n",
    "  - `-`     左对齐；正数前无符号，负数前加负号\n",
    "  - 空格   右对齐；正数前加空格，负数前加负号\n",
    "  - `0`     右对齐；正数前无符号，负数前加负号；用0填充空白处\n",
    "\n",
    "- `width`： 取值为整数，表示占位宽度\n",
    "- `precision`： 取值为整数，表示保留小数位数\n",
    "- `type`： 表示占位数据类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 常用类型符号\n",
    "\n",
    "| 符号 | 类型 | 示例 | 输出|\n",
    "| :--- | :---- |:--- |:---|\n",
    "| `c`   | 字符或ASCII码值 | `'%c%c' % (80, 121)` | `'Py'` |\n",
    "| `s`   | 字符串   | `'Hello %s' % 'Python'` | `'Hello Python'` |\n",
    "| `d`     | 整数   | `'%d-%d' % (4, 2)` | `'4-2'` |\n",
    "| `f`     | 浮点数 | `'pi is %f' % 3.14` | `'pi is 3.140000'` |\n",
    "| `e`     | 科学计数法   | `'pi is %e' % 3.14` | `'pi is 3.140000e+00'` |\n",
    "| `g`     | 相当于`f`或`e` | `'pi is %g' % 3.14` | `'pi is 3.14'` |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 示例\n",
    "\n",
    "|功能| 示例 |输出|\n",
    "|:---|:---|:---|\n",
    "|以字典的方式传递占位值|`'%(n1)d + %(n2)d = %(rst)d' % {'n1':3, 'n2': 2, 'rst': 5}`|`'3 + 2 = 5'`|\n",
    "|指定小数位数和总宽度|`'pi is %10.3f' % 3.1415926`|`'pi is      3.143'`|\n",
    "|指定宽度，不足左侧补0|`'pi is %010.3f' % 3.1415926`|`'pi is 000003.143'`|\n",
    "|左对齐|`'pi is %-10.3f' % 3.1415926`|`'pi is 3.143     '`|"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 利用`str.format`方法格式化字符串\n",
    "\n",
    "- 利用`str.format`方法格式化字符串要更加灵活\n",
    "- 占位符为`{}`，形式为 `{:format_spec}`\n",
    "\n",
    "`format_spec`常用的语法形式为`[[fill]align][sign][0][width][,][.precision][type]`\n",
    "\n",
    "- `fill`：填充符号\n",
    "- `align`：对齐方式，取值可以是\n",
    "  - `<`：左对齐\n",
    "  - `>`：右对齐\n",
    "  - `=`：仅对数字有效，在`sign`和数字之间填充符号\n",
    "  - `^`：居中对齐"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- `sign`：符号，取值可以是\n",
    "  - `+`：正数前有`+`，负数前有`-`\n",
    "  - `-`：负数前有`-`，该取值为默认值\n",
    "  - 空格：正数前有空格，负数前有`-`\n",
    "- `0`：在数值前补0，仅对数值有效\n",
    "- `width`：占位宽度\n",
    "- `,`：仅对数字有效，表示千位分隔符\n",
    "- `precision`：表示有效数字位数（注意与`%`符号格式化有区别）\n",
    "- `type`：占位数据类型，常用类型与`%`符号格式化字符串一致，默认取值为`d`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 示例\n",
    "\n",
    "| 功能                  | 示例                                  | 输出                 |\n",
    "| :--------------------- | :------------------------------------- | :-------------------- |\n",
    "| 指定小数位数和总宽度  | `'pi is {:10.3}'.format(3.1415926)`   | `'pi is       3.14'` |\n",
    "| 指定宽度，不足左侧补0 | `'pi is {:010.3}'.format(3.1415926)`  | `'pi is 0000003.14'` |\n",
    "| 左对齐                | `'pi is {:<10.3}'.format(3.1415926)`  | `'pi is 3.14      '` |\n",
    "| 左对齐，填充`*`       | `'pi is {:*<10.3}'.format(3.1415926)` | `'pi is 3.14******'` |\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 按顺序替换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The sercret numbers are 9, 5, 2, and 7'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    " 'The sercret numbers are {}, {}, {}, and {}'.format(9, 5, 2, 7)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " - 按索引替换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The sercret numbers are 7, 2, 5, and 9'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'The sercret numbers are {3}, {2}, {1}, and {0}'.format(9, 5, 2, 7)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 按标识符替换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The sercret numbers are 9, 5, 2, and 7'"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'The sercret numbers are {one}, {two}, {three}, and {four}'.format(one=9, two=5, three=2, four=7)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 利用f-Strings格式化字符串\n",
    "\n",
    "- f-Strings格式化字符串与`str.format`方法非常相似。f-String的语法形式为`{表达式}`或者`{表达式:format_spec}`\n",
    "- `format_spec`的语法形式与`str.format`完全一样\n",
    "- f-Strings与`str.format`方法的区别\n",
    "  - 字符串前加`f`以标识出其为一个格式字符串\n",
    "  - 不使用`format`函数，而直接将表达式放置在`:`前"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "| 功能                  | 示例                          | 输出                 |\n",
    "| :--------------------- | :----------------------------- | :-------------------- |\n",
    "| 指定小数位数和总宽度  | `f'pi is {3.1415926:10.3}'`   | `'pi is       3.14'` |\n",
    "| 指定宽度，不足左侧补0 | `f'pi is {3.1415926:010.3}'`  | `'pi is 0000003.14'` |\n",
    "| 左对齐                | `f'pi is {3.1415926:<10.3}'`  | `'pi is 3.14      '` |\n",
    "| 左对齐，填充`*`       | `f'pi is {3.1415926:*<10.3}'` | `'pi is 3.14******'` |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- Python 3.8中的新功能"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'变量的取值为 x=3, y=2'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    " x, y = 3, 2\n",
    "f'变量的取值为 x={x}, y={y}'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'变量的取值为 x=3, y=2'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    " f\"变量的取值为 {x=}, {y=}\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 3.7 二进制序列\n",
    "\n",
    "### 3.7.1 字节串的原理\n",
    "\n",
    "- 二进制序列的类型\n",
    "  - 字节串`bytes`（或称为字节码）\n",
    "    - 不可变类型\n",
    "  - 字节数组`bytearray`\n",
    "    - 可变类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "- 二进制序列 VS 字符串\n",
    "  - 二进制序列不是字符串\n",
    "  - 字符串的最终存储形式为二进制序列，其他数据如图像、音频、视频等也以二进制序列的形式存储\n",
    "  - 一个字节包含8位，ASCII码中的一个符号也占用一个字节\n",
    "    - 如果字节串的内容都是ASCII符号，则可以直接在字符串前加前缀`b`来构建字节串"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "\n",
    "- 字节串在显示的时候将一个字节的8位分为两部分，每部分4位，用一个十六进制数字表示\n",
    "  - 字节串的中每个元素本来面目是两个十六进制数字"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.7.2 字节串的应用\n",
    "\n",
    "- Python 3.x默认编码方式为utf-8，每个中文字符用3个字节存储\n",
    "- 下例中，“很”字的二进制序列表示为 \\xe5\\xbe\\x88\n",
    "  - \\x 表示十六进制数，第一个字节的十六进制数值为 e5\n",
    "  - 每个 ASCII 字符占 1 个字节，每个中文占 3 个字节，因此字节串的长度为 18"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'Python\\xe5\\xbe\\x88\\xe6\\x9c\\x89\\xe6\\x84\\x8f\\xe6\\x80\\x9d'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'Python很有意思'.encode('utf-8')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18\n",
      "[80, 121, 116, 104, 111, 110, 229, 190, 136, 230, 156, 137, 230, 132, 143, 230, 128, 157]\n"
     ]
    }
   ],
   "source": [
    "bs =[i for i in bs]\n",
    "print(len(bs))\n",
    "print(bs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 字节串(bytes)只负责以字节序列的形式来记录数据，至于这些数据到底表示什么 内容，完全由数据自身的编码格式决定\n",
    "- 采用正确的字符集，字符串可以转换成字 节串;反过来，字节串也可以恢复成对应的字符串\n",
    "- 图像可以用适当的编码方式 保存为字节串，而字节串也可以用同样的编码方式恢复成图像"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 3.8 高级数据结构\n",
    "\n",
    "###  3.8.1 `collection`模块\n",
    "\n",
    "- `ChainMap`\n",
    "  - `ChainMap`对多个字典对象进行整合，并且实现了大部分字典的方法，能够将多个字典当一个字典来使用\n",
    "  - 字典中的第一个称为子map，其他的称为父map。`ChainMap`中除了大部分字典操作字典的方法，还有如下几个常用的属性或方法：\n",
    "    - `maps`：返回所有字典构成的列表\n",
    "    - `parents`：返回所有的父map构成的列表\n",
    "    - `new_child`方法：返回一个新的`ChainMap`对象，其中包含一个空的子map，原对象中的字典都被作为父map\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'a': 1, 'b': 4}, {'c': 2, 'd': 8}]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import ChainMap\n",
    "m1 = {'a': 1, 'b':4}\n",
    "m2 = {'c': 2, 'd':8}\n",
    "cm = ChainMap(m1, m2)\n",
    "cm.maps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ChainMap({'a': 1, 'b': 4, 'c': 0}, {'c': 2, 'd': 8})\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "ChainMap({}, {'a': 1, 'b': 4, 'c': 0}, {'c': 2, 'd': 8})"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cm['c'] = 0              # 只能有子map能修改\n",
    "print(cm)\n",
    "cm.new_child()           # 得到一个新的ChainMap对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- `Counter`\n",
    "  - `Counter`用于统计一个可迭代对象中不同元素出现的频次。`Counter`的操作方法类似于字典，还包含了一些有用的属性或方法。常用的有：\n",
    "\n",
    "    - `elements`方法：返回所有元素组成的列表，重复元素会出现多次\n",
    "    - `most_common`方法：返回出现频最多的元素及频次的元组组成的列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({' ': 8, 'o': 4, 'e': 2, 'u': 2, 'r': 2, 'a': 2, 'T': 1, 'h': 1, 'q': 1, 'i': 1, 'c': 1, 'k': 1, 'b': 1, 'w': 1, 'n': 1, 'f': 1, 'x': 1, 'j': 1, 'm': 1, 'p': 1, 's': 1, 'v': 1, 'l': 1, 'z': 1, 'y': 1, 'd': 1, 'g': 1, '.': 1})\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[(' ', 8),\n",
       " ('o', 4),\n",
       " ('e', 2),\n",
       " ('u', 2),\n",
       " ('r', 2),\n",
       " ('a', 2),\n",
       " ('T', 1),\n",
       " ('h', 1),\n",
       " ('q', 1),\n",
       " ('i', 1),\n",
       " ('c', 1),\n",
       " ('k', 1),\n",
       " ('b', 1),\n",
       " ('w', 1),\n",
       " ('n', 1),\n",
       " ('f', 1),\n",
       " ('x', 1),\n",
       " ('j', 1),\n",
       " ('m', 1),\n",
       " ('p', 1),\n",
       " ('s', 1),\n",
       " ('v', 1),\n",
       " ('l', 1),\n",
       " ('z', 1),\n",
       " ('y', 1),\n",
       " ('d', 1),\n",
       " ('g', 1),\n",
       " ('.', 1)]"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import Counter\n",
    "s = 'The quick brown fox jumps over a lazy dog.'\n",
    "c = Counter(s)\n",
    "print(c)\n",
    "c.most_common()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- `deque`\n",
    "  - `deque`是一种双向队列，即可以从任意一端添加或删除元素。`deque`可以基于一个可迭代对象创建，并指定队列的长度。常用的方法有：\n",
    "    - `append`：在右端添加元素\n",
    "    - `appendleft`：在左端添加元素\n",
    "    - `pop`：弹出右端元素\n",
    "    - `popleft`：弹出左端元素\n",
    "    - `extend`：从右端扩展元素\n",
    "    - `extendleft`：从左端扩展元素\n",
    "    - `clear`：清空队列\n",
    "    - `reverse`：返转队列元素顺序\n",
    "    - `rotate`：移动全部队列元素，参数大于0向右移动，参数小于0向左移动\n",
    "    - `count`：统计队列中元素的频次"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.8.1 `array.array`\n",
    "- `array`模型中的`array`类型的使用方法与`list`非常相似，区别在于其中的元素必须具有相同的数据类型。这与静态语言中的数组类似。在创建`array.array`对象时，必须利用`typecode`参数指明要存储的元素的类型。`array.array`支持的数据类型见下表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "array('i', [1, 4, 2, 8, 5, 7])\n",
      "i\n"
     ]
    }
   ],
   "source": [
    "import array\n",
    "int_numbs = array.array('i',[1, 4, 2, 8, 5, 7])\n",
    "print(int_numbs)\n",
    "print(int_numbs.typecode)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "| 类型码 | C类型              | Python类型        | 最小字节数 |\n",
    "| :----- | :----------------- | :---------------- | :--------- |\n",
    "| `'b'`  | signed char        | int               | 1          |\n",
    "| `'B'`  | unsigned char      | int               | 1          |\n",
    "| `'u'`  | Py_UNICODE         | Unicode character | 2          |\n",
    "| `'h'`  | signed short       | int               | 2          |\n",
    "| `'H'`  | unsigned short     | int               | 2          |\n",
    "| `'i'`  | signed int         | int               | 2          |\n",
    "| `'I'`  | unsigned int       | int               | 2          |\n",
    "| `'l'`  | signed long        | int               | 4          |\n",
    "| `'L'`  | unsigned long      | int               | 4          |\n",
    "| `'q'`  | signed long long   | int               | 8          |\n",
    "| `'Q'`  | unsigned long long | int               | 8          |\n",
    "| `'f'`  | float              | float             | 4          |\n",
    "| `'d'`  | double             | float             | 8          |\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 3.8.3 其他有用的数据结构\n",
    "- 除了前文介绍的数据结构之外，Python还内置了很多更加复杂的数据结构或更多的实现类型，参见下表\n",
    "\n",
    "\n",
    "| 模块      | 特征描述                                     |\n",
    "| --------- | -------------------------------------------- |\n",
    "| `heapq`   | 堆（heap）或树形数据结构                     |\n",
    "| `bisect`  | 有序列表的高效操作（插入、删除）             |\n",
    "| `weakref` | 帮助创建Python引用，但不会阻止对象的销毁操作 |\n",
    "| `queue`   | 提供了多种队列的实现类型                     |\n"
   ]
  }
 ],
 "metadata": {
  "author": "liuchen",
  "celltoolbar": "幻灯片",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.1"
  },
  "rise": {
   "enable_chalkboard": true,
   "footer": "",
   "progress": true,
   "scroll": true,
   "slideNumber": true
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "url": "https://github.com/hitlic/python_book"
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
